import javax.security.sasl.SaslException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        resp.setContentType("text/html; charset=utf8");
        System.out.println("你好 Java");
        resp.getWriter().write("你好 java");
    }
    // 第一个 Servlet 程序
    // 1. 创建项目
    // 2. 引入依赖
    // Maven 项目创建完毕后, 会自动生成一个 pom.xml 文件.
    //我们需要在 pom.xml 中引入 Servlet API 依赖的 jar 包.
    //  选择版本. 一般我们使用 3.1.0 版本 ; 把中央仓库中提供的 xml 复制到项目的 pom.xml 中
    // 3. 创建目录 1) 创建 webapp 目录  2)创建WEB-INF 3)创建 web.xml
    //  4. 编写代码
    // 5. 打包程序
    // 6. 部署程序 把 war 包拷贝到 Tomcat 的 webapps 目录下. ; 启动 Tomcat , Tomcat 就会自动把 war 包解压缩.
    // 7. 验证程序

    // servlet API 里面的详细情况
    // 课堂上重点学习3个类. 掌握了这三个类, 就可以完成大部分的Servlet 的开发了
    // 1. HttpServlet

    // HttpServelt 写一个Servlet代码, 往往都是要继承这个类,重写里面的方法. 目的就是把咱们自己定义的代码,插入到tomcat中
    // Servlet 这里的代码, 只需要继承 httpServlet就行了. 不必写一个main方法.
    // (如果一个程序比喻成一辆汽车, main 方法就是发动机. 那么是否存在一辆车,没有发动机也能跑? 有, 火车车厢
    // (只是火车头里面有发动机), 车斗. 所以 Servlet 程序 没写main , 咱们写的这个程序不是直接运行的 而是放到 Tomcat
    // 上运行的, tomcat这个程序里面有main,tomcat就是火车头.写的 webapp就是车厢)

    /*
     * 在 tomcat 中, 就有形如一下这样的代码: (注意 是在tomcat 中)
     *  先通过 tcp socket 读取请求. http 也是基于 tcp
     * String requestString = readRequest();
     *
     * 解析这个请求
     * HttpServletRequest req = pare(requestString)
     *
     * 构造空的响应对象
     * HttpServletResponse = new HttpServletResponse();
     *
     * 创建一个HttpServlet 对象
     * HttpServlet s = new HelloServlet(); // Tomcat 能够自动的 new 出一个咱们写的一个子类.(这里具体是怎么 new 出来,暂时不关注)
     * s.doGet(req,resp); // 调用到这个方法 这就执行到咱们的代码
     * // 进一步的,也就是相当于 , 让咱们的代码"嵌入到" tomcat中运行
     *  相当与在处理一次请求的过程中, Tomcat 完成了 99% 的工作. 剩下1%,有咱们写代码来完成(这1%主要是为了解决不同的业务场景)
     * 把得到的响应返回给浏览器
     */

    // ****** HttpServlet 里面重要的方法  ******
    // init    在 HttpServlet 实例化之后被调用一次 (通过这个方法 完成初始化操作)
    // destroy 在 HttpServlet 实例不再使用的时候带哦用一次 (往往是用来是释放资源 , 在servelt结束之前使用的)
    // service 在 Http 请求的时候调用 ( 从这里开始上面的这三个方法是最重要的 )
    // (在子类重写这些方法之后, 这些方法也都是不需要咱们手动调用的, 都是 tomcat 在合适的时机自行调用的)
    // (**** 这三个方法以及他们所调用的时机 称作 Servlet 的生命周期(静待你面试题) **** 谈的就是这三个方法各自调用的时机)
    // (再简化生命周期的意思就是 : 在什么时间点做什么事情) (这三个方法在实际开发中很少会用到, 一般都是出现在面试题中)
    // (init 还算比较有用)
    // (servlet 一般会被 doGet / doPost 替代)
    // (destory 非常尴尬, 说了不算, 算了不说.. 这个方法大概率是执行不到的.
    // 一个Servlet 不用了, 说明 Tomcat 要关闭了.
    //  Tomcat 关闭有两种方式:
    //  1. 直接干掉 Tomcat 进程(比如直接在 任务管理器中 结束任务. 或者直接 点 x 完全来不及调用 destroy 的)) 最长用的方法还是第一个
    // 2.通过在 8005 管理端口 , 给 tomcat 发送一个 "停机" 指令, 这个时候是能够执行到 derrtroy 的
    // doGet 收到 GET 请求的时候调用(由 service 方法调用)
    // doPost 收到 POST 请求的时候 调用(由 service 方法调用)
    // doPut/doDelet/doOptions/.. 收到其他请求的时候调用(由 service 方法调用)
    // (如果不重写 serrbice 在父类中, 自己的 service 就会根据请求的方法,来分别调用)
    // 以上这几个方法都是可以在子类中重写的

    // 2. HttpServletRequest
    // 表示了一个 HTTP 请求

    // ****常用代码**** (对照着前面的 http 协议)
    // String getProtocol()   返回请求协议的名称和版本。  (请求中 首行的 版本号)
    // String getMethod()     返回请求的 HTTP 方法的名称，例如，GET、POST 或 PUT。 (请求的首行的第一个部分)
    // String getRequestURI()  从协议名称直到 HTTP 请求的第一行的查询字符串中，返回该请求的 URL 的一部分。 (请求的首行中的第二个部分)
    // (URI 是唯一资源标识符(相当于身份证号) URL 唯一资源定位/地址符(相当于你的地址) , 正因为这两个概念的核心词 唯一 也经常会使用URL来作为URI)
    // String getContextPath() 返回指示请求上下文的请求 URI 部分。(获得第一季路径)
    // String getQueryString() 返回包含在路径后的请求 URL 中的查询字符串。 (获得键值对)

    // Enumeration getParameterNames() 返回一个 String 对象的枚举，包含在该请求中包含的参数的名称。
    //**** String getParameter(String name)  以字符串形式返回请求参数的值，或者如果参数不存在则返回null。**** (这个是最常用的, 一个key 获得一个值)
    //(在服务器这边获取到的请求中的参数.(Query String) query string 中的键值对,都是程序员自定义的.
    // 在实际开发中都会非常广泛使用的 query string(就是针对这次请求他的一些补充说明) 这样的机制)
    // String[] getParameterValues(String name)  返回一个字符串对象的数组，包含所有给定的请求参数的值，如果参数不存在则返回 null。(key 的名字一样, 一个key 有多个值)
    // 这几个方法是一组, 这几个方法都是根据我们的 query string 本质上是键值对, 一般都是要根据 key 来获取 value
    // 很少把query string 作为整体来使用

    // Enumeration getHeaderNames()  返回一个枚举，包含在该请求中包含的所有的头名。
    // String getHeader(String name) 以字符串形式返回指定的请求头的值。
    // 这两个是一组  http 请求 header 部分 也是键值对, 也需要根据key 获取 value

    // String getCharacterEncoding()  返回请求主体中使用的字符编码的名称。
    // String getContentType()  返回请求主体的 MIME 类型，如果不知道类型则返回 null。
    // int getContentLength()  以字节为单位返回请求主体的长度，并提供输入流，或者如果长度未知则返回 -1。
    // 这几个是一组, 都是 getHeader 进行了简单的封装

    // InputStream getInputStream() 用于读取请求的 body 内容. 返回一个 InputStream 对象.
    // 这个方法用来得到一个流对象, 读取这个流对象, 就能得到整个请求的body(很多时候 在代码中表示不定长的数据的时候 经常使用流对象)
    // 使用流对象既可以 一次处理一点也可以一次处理完
    // 也可以更好的兼容二进制数据

    // 上面介绍的方法都是 get系列的方法(都是 读 方法)
    // 没有 set 系列(没有 写 方法)
    // 拿到的 HttpServletRequest, 这里的数据都是来自于客户端发来的. 这些数据的内容已经确定下来, 程序员是不应该修改的



    // 3. HttpServletResponse
    // 表示 http 的响应 (里面的api都是set系列的方法 )
    // ***** 常用代码*****
    //  void setStatus(int sc)                      为该响应设置状态码。
    //  void setHeader(String name,String value)  设置一个带有给定的名称和值的 header. 如果 name 已经存在,则覆盖旧的值
    //  void addHeader(String name, String value)  添加一个带有给定的名称和值的 header. 如果 name 已经存在,不覆盖旧的值, 并列添加新的键值对
    // void setContentType(String type)             设置被发送到客户端的响应的内容类型。
    // void setCharacterEncoding(String charset)   设置被发送到客户端的响应的字符编码（MIME 字符集）例如，UTF-8
    // void sendRedirect(String location)    使用指定的重定向位置 URL 发送临时重定向响应到客户端  (直接构造重定向响应)
    // PrintWriter getWriter()               用于往 body 中写入文本格式数据   (响应的 body 也是通过流对象来进行体现的, 此处是写入, 要使用输出流)
    // OutputStream getOutputStream()        用于往 body 中写入二进制格式数据.

    // 掌握 上述 api 之后, 就可以编写具体的网站了

    // 先来一个最简单的网站, 只有一个页面 (表白墙)

}
